/**
 * 手写Promise
 * 
 * 状态机对象
 * 
 * 状态对象 + 链式调用 + 异步
 */

class MyPromise {
  // 状态对象 + 异步
  constructor (exe) {
    this.value = undefined
    this.status = 'pending'
    this.successQueue = [] // node：存在两种想法，想法1：首个promise包含后面所有的回调队列；
                           // 想法2： 每个promise都有指向下一个promise的链接，每个promise有独立的一个成功回调/失败回调
    this.failureQueue = []
    const resolve = (val) => {
      const doResolve = (value) => {
        if (this.status === 'pending') {
          this.status = 'success'
          this.value = value
  
          while (this.successQueue.length) {
            const cb = this.successQueue.shift()
  
            cb && cb(this.value)
          }
        }
      }

      setTimeout(()=>doResolve(val), 0)
    }

    const reject = (err) => {
      const doReject = (value) => {
        if (this.status === 'pending') {
          this.status = 'failure'
          this.value = value
  
          while (this.failureQueue.length) {
            const cb = this.failureQueue.shift()
  
            cb && cb(this.value)
          }
        }
      }

      setTimeout(()=>doReject(err), 0)
    }

    exe(resolve, reject)
  }

  // 链式调用
  then (success = (value) => value, failure = (value) => value) {
    return new MyPromise((resolve, reject) => {
      // 分别包装 then的成功回调
      const successFn = (value) => {
        try {
          const result = success(value)
          
          // 若then返回的依然是promise对象，那么返回一个新的promise，新的promise和此promise状态一致; 
          // 这里直接把当前promise 的resolve, reject传给了新promise的回调回调队列
          result instanceof MyPromise ? result.then(resolve, reject) : resolve(result)
        } catch (err) {
          reject(err)
        }
      }

      // 分别包装 then的时代回调
      const failureFn = (value) => {
        try {
          const result = failure(value)
          
          result instanceof MyPromise ? result.then(resolve, reject) : resolve(result)
        } catch (err) {
          reject(err)
        }
      }

      if (this.status === 'pending') {
        this.successQueue.push(successFn)
        this.failureQueue.push(failureFn)
      } else if (this.status === 'success') {
        success(this.value) //这里已经是成功状态了，直接执行用户的回调；注意return new MyPromise()是顶层代码
      } else {
        failure(this.value)
      }
    })
  }

  catch () {

  }
} 


// 测试代码
const pro = new MyPromise((resolve, reject) => {
  setTimeout(resolve, 1000)
  setTimeout(reject, 2000)
})

pro
  .then(() => {
    console.log('2_1')
    const newPro = new MyPromise((resolve, reject) => {
      console.log('2_2')
      setTimeout(()=>resolve('hello'), 2000)
    })
    console.log('2_3')
    return newPro
  })
  .then(
    (str) => {
      console.log('2_4', str)
    },
    () => {
      console.log('2_5')
    }
  )
  
pro
  .then(
    data => {
      console.log('3_1')
      throw new Error()
    },
    data => {
      console.log('3_2')
    }
  )
  .then(
    () => {
      console.log('3_3')
    },
    e => {
      console.log('3_4')
    }
  )